#include <stdio.h>
#include <omp.h>

#define SIZE 100

// func1
void func1(double A[SIZE][SIZE]) {
    #pragma omp parallel for
    for (int i = 0; i < SIZE; ++i) {
        for (int j = 0; j < SIZE; ++j) {
            int thread_id = omp_get_thread_num();
            printf("Thread %d is processing A[%d][%d] in func1\n", thread_id, i, j);
            A[i][j] = A[i][j] + 1;
        }
    }
}

// func2
void func2(double A[SIZE][SIZE]) {
    #pragma omp parallel for
    for (int i1 = 0; i1 < SIZE; i1 += 4) {
        for (int j1 = 0; j1 < SIZE; j1 += 16) {
            for (int i2 = i1; i2 < i1 + 4; ++i2) {
                for (int j2 = j1; j2 < (j1 + 16 > SIZE? SIZE : j1 + 16); ++j2) {
                    int thread_id = omp_get_thread_num();
                    printf("Thread %d is processing A[%d][%d] in func2\n", thread_id, i2, j2);
                    A[i2][j2] = A[i2][j2] + 1;
                }
            }
        }
    }
}

// func3
void func3(double A[SIZE][SIZE]) {
    #pragma omp parallel for
    for (int i = 0; i < SIZE; i += 4) {
        for (int j = 0; j < SIZE; j += 16) {
            int end_i = (i + 4 > SIZE)? SIZE : i + 4;
            int end_j = (j + 16 > SIZE)? SIZE : j + 16;
            for (int ii = i; ii < end_i; ++ii) {
                for (int jj = j; jj < end_j; ++jj) {
                    int thread_id = omp_get_thread_num();
                    printf("Thread %d is processing A[%d][%d] in func3\n", thread_id, ii, jj);
                    A[ii][jj] = A[ii][jj] + 1;
                }
            }
        }
    }
}

// func4
void func4(double A[SIZE][SIZE]) {
    #pragma omp parallel for
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j += 16) {
            int end_j = (j + 16 > SIZE)? SIZE : j + 16;
            for (int k = j; k < end_j; k++) {
                int thread_id = omp_get_thread_num();
                printf("Thread %d is processing A[%d][%d] in func4\n", thread_id, i, k);
                A[i][k] = A[i][k] + 1;
            }
        }
    }
}

// func5
void func5(double A[SIZE][SIZE]) {
    #pragma omp parallel for
    for (int i = 0; i < SIZE; i += 4) {
        for (int j = 0; j < SIZE; j++) {
            int start_i = i;
            int end_i = (i + 4 > SIZE)? SIZE : i + 4;
            for (int ii = start_i; ii < end_i; ++ii) {
                int thread_id = omp_get_thread_num();
                printf("Thread %d is processing A[%d][%d] in func5\n", thread_id, ii, j);
                A[ii][j] = A[ii][j] + 1;
            }
        }
    }
}

// func6
void func6(double A[SIZE][SIZE]) {
    #pragma omp parallel for
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            int thread_id = omp_get_thread_num();
            printf("Thread %d is processing A[%d][%d] in func6\n", thread_id, i, j);
            A[i][j] = A[i][j] + 1;
        }
    }
}

int main() {
    double A[SIZE][SIZE];
    // 初始化数组
    for (int i = 0; i < SIZE; ++i) {
        for (int j = 0; j < SIZE; ++j) {
            A[i][j] = 0;
        }
    }

    // 调用 func1 函数
    func1(A);
    printf("After func1:\n");
    for (int i = 0; i < 5; ++i) {
        for (int j = 0; j < 5; ++j) {
            printf("%f ", A[i][j]);
        }
        printf("\n");
    }

    // 重新初始化数组
    for (int i = 0; i < SIZE; ++i) {
        for (int j = 0; j < SIZE; ++j) {
            A[i][j] = 0;
        }
    }

    // 调用 func2 函数
    func2(A);
    printf("After func2:\n");
    for (int i = 0; i < 5; ++i) {
        for (int j = 0; j < 5; ++j) {
            printf("%f ", A[i][j]);
        }
        printf("\n");
    }

    // 再次重新初始化数组
    for (int i = 0; i < SIZE; ++i) {
        for (int j = 0; j < SIZE; ++j) {
            A[i][j] = 0;
        }
    }

    // 调用 func3 函数
    func3(A);
    printf("After func3:\n");
    for (int i = 0; i < 5; ++i) {
        for (int j = 0; j < 5; ++j) {
            printf("%f ", A[i][j]);
        }
        printf("\n");
    }

    // 重新初始化数组
    for (int i = 0; i < SIZE; ++i) {
        for (int j = 0; j < SIZE; ++j) {
            A[i][j] = 0;
        }
    }

    // 调用 func4 函数
    func4(A);
    printf("After func4:\n");
    for (int i = 0; i < 5; ++i) {
        for (int j = 0; j < 5; ++j) {
            printf("%f ", A[i][j]);
        }
        printf("\n");
    }

    // 重新初始化数组
    for (int i = 0; i < SIZE; ++i) {
        for (int j = 0; j < SIZE; ++j) {
            A[i][j] = 0;
        }
    }

    // 调用 func5 函数
    func5(A);
    printf("After func5:\n");
    for (int i = 0; i < 5; ++i) {
        for (int j = 0; j < 5; ++j) {
            printf("%f ", A[i][j]);
        }
        printf("\n");
    }

    // 重新初始化数组
    for (int i = 0; i < SIZE; ++i) {
        for (int j = 0; j < SIZE; ++j) {
            A[i][j] = 0;
        }
    }

    // 调用 func6 函数
    func6(A);
    printf("After func6:\n");
    for (int i = 0; i < 5; ++i) {
        for (int j = 0; j < 5; ++j) {
            printf("%f ", A[i][j]);
        }
        printf("\n");
    }

    return 0;
}    